#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <errno.h>
#include <time.h>

#include "priority.h"

//配置选项可为ON或者OFF
//进入build目录，cmake -DCROSS_COMPILE=ON -DGENERATE_LIB=ON ../
//编译并运行
//make && ./priority_queue

//调试（在结果中可能看到map对应的优先级是错误的，原因是打印函数被写线程中断后，map值发生了变化，而优先级值未更新）
//在priority.c中的priority_queue_out函数加入
//         #endif/*GNUC_MIN_VERSION_SUPPORT*/
// +++ printf("%02x-%d-", _priority_queue->map, z);
//         if(z >= PRIORITY_LEVEL_MAX)

//     }
// +++ printf("%d\r\n", *pBuf);
//     return PQ_SUCCESS;

__attribute__((used))
static void* task_read(void *para);
__attribute__((used))
static void* task_write(void *para);

struct priority_queue_t *priority_queue;

pthread_t thd_rd[1],thd_wr[3];

#define IF_USE_RD_LOCK 1U
#define IF_USE_WR_LOCK 1U
#if IF_USE_RD_LOCK
pthread_mutex_t thd_rd_write_file_mutex;
#endif
#if IF_USE_WR_LOCK
pthread_mutex_t thd_wr_write_file_mutex;
#endif

//必须是2的幂次方
#define TEST_DATA_SIZE 32
uint8_t test_write_data[TEST_DATA_SIZE] = {0},test_read_data[TEST_DATA_SIZE << 1] = {0};

int main(int argc,char *argv[])
{
    int ret = -1;

    ret = priority_queue_init(&priority_queue);
    if(PQ_SUCCESS != ret)
    {
        printf("priority queue init failed..\r\n");
        return -1;
    }
    ret = priority_queue_add(priority_queue, 0, 512, PQ_TYPE_STREAM);
    if(PQ_SUCCESS != ret)
    {
        printf("line:%d,priority queue add failed..\r\n", __LINE__);
    }
    ret = priority_queue_add(priority_queue, 2, 512, PQ_TYPE_STREAM);
    if(PQ_SUCCESS != ret)
    {
        printf("line:%d,priority queue add failed..\r\n", __LINE__);
    }
    ret = priority_queue_add(priority_queue, 5, 512, PQ_TYPE_STREAM);
    if(PQ_SUCCESS != ret)
    {
        printf("line:%d,priority queue add failed..\r\n", __LINE__);
    }

#if 0
    for(uint32_t i = 0;i < sizeof(thd_rd) / sizeof(*thd_rd);i++)
    {
        pthread_create(&thd_rd[i],NULL,task_read,NULL);
    }
    for(uint32_t i = 0;i < sizeof(thd_wr) / sizeof(*thd_wr);i++)
    {
        pthread_create(&thd_wr[i],NULL,task_write,NULL);
    }

    for(uint32_t i = 0;i < sizeof(thd_wr) / sizeof(*thd_wr);i++)
    {
        pthread_join(thd_wr[i],NULL);
    }
    for(uint32_t i = 0;i < sizeof(thd_rd) / sizeof(*thd_rd);i++)
    {
        pthread_join(thd_rd[i],NULL);
    }
#else
    uint32_t idx = 0;
    uint16_t ret_len;

    printf("%s\r\n", priority_queue_is_empty(priority_queue) ? "true" : "false");

    test_write_data[0] = 100;
    priority_queue_in(priority_queue,0,test_write_data,1);
    test_write_data[0] = 99;
    priority_queue_in(priority_queue,2,test_write_data,1);
    test_write_data[0] = 98;
    priority_queue_in(priority_queue,5,test_write_data,1);
    test_write_data[0] = 99;
    priority_queue_in(priority_queue,2,test_write_data,1);
    test_write_data[0] = 98;
    priority_queue_in(priority_queue,5,test_write_data,1);
    test_write_data[0] = 100;
    priority_queue_in(priority_queue,0,test_write_data,1);

    printf("%s\r\n", priority_queue_is_empty(priority_queue) ? "true" : "false");

    priority_queue_out(priority_queue,&test_read_data[idx++],1,&ret_len);
    priority_queue_out(priority_queue,&test_read_data[idx++],1,&ret_len);
    priority_queue_out(priority_queue,&test_read_data[idx++],1,&ret_len);
    priority_queue_out(priority_queue,&test_read_data[idx++],1,&ret_len);
    priority_queue_out(priority_queue,&test_read_data[idx++],1,&ret_len);

    printf("%s\r\n", priority_queue_is_empty(priority_queue) ? "true" : "false");
    
    priority_queue_out(priority_queue,&test_read_data[idx++],1,&ret_len);

    printf("%s\r\n", priority_queue_is_empty(priority_queue) ? "true" : "false");
    
    printf("test_read_data:\r\n");
    for(uint32_t i = 0;i < idx;i++)
    {
        if(i && (!(i % 10)))
        {
            printf("\r\n");
        }
        printf("%d ",test_read_data[i]);
    }
    printf("\r\n");
#endif
    priority_queue_destroy(priority_queue);

    return 0;
}

void* task_read(void *para)
{
    uint32_t ret;
    uint16_t rd_len = 0;

    for(;;)
    {
        ret = priority_queue_out(priority_queue,test_read_data,1,&rd_len);
        if((PQ_SUCCESS != ret) || (!rd_len))
        {
            if(errno == ETIMEDOUT)
            {
                continue;
            }
        }
        else
        {
            // printf("test_read_data:\r\n");
            // for(uint32_t i = 0;i < rd_len;i++)
            // {
            //     if(i && (!(i % 10)))
            //     {
            //         printf("\r\n");
            //     }
            //     printf("%d ",test_read_data[i]);
            // }
            // printf("\r\n");
        }
    }

    return (void *)0;
}

void* task_write(void *para)
{
    for(;;)
    {
        if(pthread_equal(pthread_self(),thd_wr[0]))
        {
            uint8_t val = 100;

            // printf("thread 0..\r\n");
            priority_queue_in(priority_queue,0,&val,1);

            usleep(30 * 1000);
        }
        else if(pthread_equal(pthread_self(),thd_wr[1]))
        {
            uint8_t val = 99;

            // printf("thread 1..\r\n");
            priority_queue_in(priority_queue,2,&val,1);

            usleep(20 * 1000);
        }
        else if(pthread_equal(pthread_self(),thd_wr[2]))
        {
            uint8_t val = 98;

            // printf("thread 2..\r\n");
            priority_queue_in(priority_queue,5,&val,1);

            usleep(10 * 1000);
        }
    }

    return (void *)0;
}
